package com.cskaoyan.market.constrain;

import com.cskaoyan.market.exception.BizException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target(value = {PARAMETER,FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = {EnumConstrain.EnumConstrainValidator.class})
@Documented
public @interface EnumConstrain {
    // 枚举类
    Class<? extends Enum<?>> enumClass();
    // 获取枚举值的方法名
    String enumMethod();

    String message() default "";
    // 分组
    Class<?>[] groups() default {};
    // 负载
    Class<? extends Payload>[] payload() default {};

    class EnumConstrainValidator implements ConstraintValidator<EnumConstrain, Object>{
        private Class<?> enumClass;
        private String methodName;

        private Set<Object> values = new HashSet<>();

        @Override
        public void initialize(EnumConstrain constraintAnnotation) {
            this.enumClass = constraintAnnotation.enumClass();
            this.methodName = constraintAnnotation.enumMethod();
            Object[] enumConstans = this.enumClass.getEnumConstants();
            if(enumConstans == null){
                return;
            }
            Method method = BeanUtils.findMethod(enumClass,methodName);
            if(null == method){
                throw new BizException("获取枚举值方法失败");
            }
            method.setAccessible(true);
            try{
                for (Object enumConstan : enumConstans) {
                    values.add(method.invoke(enumConstan));
                }
            } catch (InvocationTargetException e) {
                throw new BizException("获取枚举值方法失败");
            } catch (IllegalAccessException e) {
                throw new BizException("获取枚举值方法失败");
            }
        }

        @Override
        public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
            if(o == null){
                return true;
            }
            if(enumClass == null || StringUtils.isEmpty(methodName)){
                return true;
            }
            return values.contains(o);
        }
    }
}
